package ricm4.ep.tp3;

import java.util.HashMap;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author fx
 */
public class Echeancier{
        private HashMap<Integer, Evenement> result=new HashMap<>();
	//private HashMap<Integer, Evenement> arrMap=new HashMap<>();
	private HashMap<Integer, Evenement> debMap=new HashMap<>();
	//private HashMap<Integer, Evenement> finMap=new HashMap<>();
        private E_Mode mode;
	private E_Mode defaultMode=E_Mode.NONPREEMPTIF;
	private E_Loi loi;
	private E_Loi defaultLoi=E_Loi.EXPONENTIELLE;
        private Pile pileAttente=new Pile();
	private final int NTACHES=1;
	private final double LAMBDA=0.2;
        
        public Echeancier(E_Mode mode, E_Loi loi){
                this.mode=mode;
		this.loi=loi;
		if(this.mode==null){
			this.mode=defaultMode;
		}
		if(this.loi==null){
			this.loi=defaultLoi;
		}
        }
	        
	public void run(){
		initEvenements();
		runGame();
	}
	
	private void initEvenements(){
		double dateArr;
		for(int i=0; i<NTACHES; i++){
			//arrMap.put(i, new Evenement(i, E_Evt.ARRIVE));
			debMap.put(i, new Evenement(i, E_Evt.DEBUT));
			//finMap.put(i, new Evenement(i, E_Evt.FIN));
		}
		
		switch(loi){
			case EXPONENTIELLE:
				dateArr=0;
				for(int i=0; i<NTACHES; i++){
					//Evenement iArr=arrMap.get(i);
					Evenement iDeb=debMap.get(i);
					//Evenement iFin=finMap.get(i);
					
					if(i!=0){
						dateArr+=Generateur.exponentielle(LAMBDA);
					}
					
					//iArr.setDate(dateArr);
					iDeb.setDate(dateArr);
					iDeb.setTempsDeService(Generateur.exponentielle(LAMBDA));
					//iFin.setDate(iDeb.getDate()+iDeb.getTempsDeService());
				}
				break;
			case DETERMINISTE:
                                dateArr=0;
                                for(int i=0; i<NTACHES; i++){
                                    Evenement iDeb=debMap.get(i);                                    
                                    if(i!=0){
                                        dateArr+=Generateur.deterministe(1);
                                    }
                                    iDeb.setDate(dateArr);
                                    iDeb.setTempsDeService(Generateur.deterministe(1));
                                }
				break;
			case UNIFORME:
				dateArr=0;
				for(int i=0; i<NTACHES; i++){
					//Evenement iArr=arrMap.get(i);
					Evenement iDeb=debMap.get(i);
					//Evenement iFin=finMap.get(i);
					
					if(i!=0){
						dateArr+=Generateur.uniforme(0, 2);
					}
					
					//iArr.setDate(dateArr);
					iDeb.setDate(dateArr);
					iDeb.setTempsDeService(Generateur.uniforme(0, 2));
					//iFin.setDate(iDeb.getDate()+iDeb.getTempsDeService());
				}
				break;
			case ERLANG:
				dateArr=0;
                                for(int i=0; i<NTACHES; i++){
                                    Evenement iDeb=debMap.get(i);
                                    
                                    if(i!=0){
                                        dateArr+=Generateur.erlang(3, 3);
                                    }
                                    iDeb.setDate(dateArr);
                                    iDeb.setTempsDeService(Generateur.erlang(3, 3));
                                }
				break;
			default:;
		}
	}
	
	private void runGame(){
		int no=0;
		int cour=0;
		int neuf;
		double dateFinCour=0;
		double dateArrNeuf;
		double TempsDeServiceNeuf;
		boolean courFini=true;
		if(NTACHES<=0 || debMap.isEmpty()){return;}
		switch(mode){
			case NONPREEMPTIF:
				pileAttente.clear();
				for(neuf=0; neuf<NTACHES; neuf++){
					dateArrNeuf=debMap.get(neuf).getDate();
					if(neuf>0 && dateArrNeuf>dateFinCour){
						courFini=true;
						result.put(cour, new Evenement(cour, E_Evt.FIN, dateFinCour, 0));
					}
					if(courFini){
						while(!pileAttente.isEmpty() && dateArrNeuf>dateFinCour){
							Evenement e=pileAttente.depiler();
							cour=e.getNumTache();
							dateFinCour=e.getDate()+e.getTempsDeService();
							result.put(no++, e);
							if(dateFinCour>=dateArrNeuf){
								result.put(no++, new Evenement(neuf, E_Evt.ARRIVE, dateArrNeuf,0));
								pileAttente.update(debMap.get(neuf).getTempsDeService());
								pileAttente.enpiler(debMap.get(neuf));
								pileAttente.update(dateFinCour-dateArrNeuf);
							}else{
								courFini=true;
								result.put(cour, new Evenement(cour, E_Evt.FIN, dateFinCour, 0));
							}
						}
						if(pileAttente.isEmpty() && dateArrNeuf>dateFinCour){
							cour=neuf;
							result.put(no++, new Evenement(cour, E_Evt.ARRIVE, dateArrNeuf,0));
							courFini=false;
							result.put(no++, debMap.get(cour));
							dateFinCour=dateArrNeuf+debMap.get(neuf).getTempsDeService();
						}
					}else{
						result.put(no++, new Evenement(neuf, E_Evt.ARRIVE, dateArrNeuf,0));
						pileAttente.update(debMap.get(neuf).getTempsDeService());
						pileAttente.enpiler(debMap.get(neuf));
						pileAttente.update(debMap.get(cour).getDate()+debMap.get(cour).getTempsDeService()-dateArrNeuf);
					}
			
					if(neuf==NTACHES-1){
						courFini=true;
						result.put(cour, new Evenement(cour, E_Evt.FIN, dateFinCour, 0));
					}
				}
				break;
			case PREEMPTIF_REPRISE:
				//todo
				pileAttente.clear();
				for(neuf=0; neuf<NTACHES; neuf++){
					
					dateArrNeuf=debMap.get(neuf).getDate();
					TempsDeServiceNeuf=debMap.get(cour).getDate()+debMap.get(cour).getTempsDeService()-debMap.get(neuf).getDate();
					
					if(pileAttente.isEmpty() && dateArrNeuf>dateFinCour){
						courFini=true;
						result.put(cour, new Evenement(cour, E_Evt.FIN, dateFinCour, 0));
					}
					else if(pileAttente.isEmpty() && dateArrNeuf<dateFinCour){
						pileAttente.enpiler(debMap.get(cour));
						pileAttente.update(TempsDeServiceNeuf);
					}
					
					while(!pileAttente.isEmpty() && dateArrNeuf>dateFinCour){
						courFini=true;
						Evenement e=pileAttente.depiler();
						cour=e.getNumTache();
						result.put(no++, e);
						dateFinCour=e.getDate()+e.getTempsDeService();
					}	
					pileAttente.enpiler(debMap.get(cour));		//此时条件为(!pileAttente.isEmpty() && dateNeufArr<dateFinCour)
					pileAttente.update(TempsDeServiceNeuf);	
					
					if(neuf==NTACHES-1){
						courFini=true;
						result.put(cour, new Evenement(cour, E_Evt.FIN, dateFinCour, 0));
					}
				}
				break;
			case PREEMPTIF_REDEMARRAGE:
				//todo
				break;
			case PREEMPTIF_REINITIALISE:
				//todo
				break;
			default:;
		}
	}
	
        public HashMap<Integer, Evenement> getResult(){
                return result;
        }
        
        public E_Mode getMode(){
                return mode;
        }
	
	public E_Loi getLoi(){
		return loi;
	}
}
